//
//  TakingPicturesViewController.swift
//  PhotoTestDemo
//
//  Created by 惠 on 2020/9/8.
//  Copyright © 2020 惠. All rights reserved.
//

import UIKit
import AVFoundation

@available(iOS 10.0, *)
class TakingPicturesViewController: UIViewController {
    private let kScreenW = UIScreen.main.bounds.size.width
    
    //是否开启闪光灯
    var isFlash: AVCaptureDevice.FlashMode = .off
    //是否拍好
    var isFinish: Bool = true
    
    //选择代理
    var selectedHandler: ((UIImage)-> Swift.Void)?
    var selectImage: UIImage?
    
    //获取当前方向
    var currentDirection: UIInterfaceOrientation = .portrait
    //颜色
    var colorType: ColorType = .defaults
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationNotification(noti:)), name: UIDevice.orientationDidChangeNotification, object: nil)
        //开始获取陀螺仪方向
        deviceOrientation.start()
    
        if TARGET_IPHONE_SIMULATOR == 1 && TARGET_OS_IPHONE == 1 {
            //模拟器
        } else {
            //真机
            creatCamera()
        }
        
        setUI()
    }
    
    @objc func deviceOrientationNotification(noti: Notification) {
        let direction = noti.userInfo!["direction"] as? UIInterfaceOrientation
        if direction?.rawValue != nil {
            currentDirection = direction!
            print(currentDirection.rawValue)
        }
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        captureSession.startRunning()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        captureSession.stopRunning()
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        let kScreenH = view.frame.height
        startButton.frame = CGRect(x: (kScreenW-64)/2, y: kScreenH - 131, width: 64, height: 64)
        finshedBtn.frame = CGRect(x: kScreenW - 56, y: kScreenH - 116, width: 28, height: 28)
        finshedLabel.frame = CGRect(x: kScreenW - 58, y: kScreenH - 84, width: 32, height: 14)
        backButton.frame = CGRect(x: 23, y: kScreenH - 116, width: 28, height: 28)
        remakeLabel.frame = CGRect(x: 23, y: kScreenH - 86, width: 28, height: 28)
    }
    
    //MARK: -设置UI
    var startImage: UIImage!
    var finshedImage: UIImage!
    func setUI() {
        view.addSubview(accordingPhoto)
        view.addSubview(startButton)
        view.addSubview(backButton)
        view.addSubview(remakeLabel)
        view.addSubview(finshedBtn)
        view.addSubview(finshedLabel)
        
        switch colorType {
        case .defaults:
            startImage = UIImage(named: "takingPictures", in: Resources.getBundle, compatibleWith: nil)
            finshedImage = UIImage(named: "finshedPictures", in: Resources.getBundle, compatibleWith: nil)
            finshedBtn.setImage(UIImage(named: "finishedVideo", in: Resources.getBundle, compatibleWith: nil), for: .normal)
        case .red:
            startImage = UIImage(named: "redTakingPictures", in: Resources.getBundle, compatibleWith: nil)
            finshedImage = UIImage(named: "redFinishedPictures", in: Resources.getBundle, compatibleWith: nil)
            finshedBtn.setImage(UIImage(named: "redFinishedVideo", in: Resources.getBundle, compatibleWith: nil), for: .normal)
        }
        startButton.setImage(startImage, for: .normal)
    }
    
    //MARK: -懒加载UI
    //陀螺仪方向
    private let deviceOrientation = DeviceOrientation()
    
    //拍照
    lazy var startButton: UIButton = {
        let startButton = UIButton(type: .custom)
        startButton.backgroundColor = .clear
        startButton.addTarget(self, action: #selector(startBtnClick(sender:)), for: .touchUpInside)
        return startButton
    }()
    
    //拍好了
    lazy var finshedBtn: UIButton = {
        let finshedBtn = UIButton(type: .custom)
        finshedBtn.backgroundColor = .clear
        finshedBtn.isHidden = true
        finshedBtn.addTarget(self, action: #selector(finshedBtnAction(sender:)), for: .touchUpInside)
        return finshedBtn
    }()
    
    lazy var finshedLabel: UILabel = {
        let finshedLabel = UILabel()
        finshedLabel.backgroundColor = .clear
        finshedLabel.text = "拍好了"
        finshedLabel.font = UIFont.systemFont(ofSize: 10)
        finshedLabel.textColor = .white
        finshedLabel.textAlignment = .center
        finshedLabel.isHidden = true
        return finshedLabel
    }()
    
    //重拍
    lazy var backButton: UIButton = {
        let backButton = UIButton(type: .custom)
        backButton.backgroundColor = .clear
        backButton.setImage(UIImage(named: "returnButton", in: Resources.getBundle, compatibleWith: nil), for: .normal)
        backButton.addTarget(self, action: #selector(returnButtonAction), for: .touchUpInside)
        backButton.isHidden = true
        return backButton
    }()
    
    lazy var remakeLabel: UILabel = {
        let remakeLabel = UILabel()
        remakeLabel.text = "重拍"
        remakeLabel.textColor = .white
        remakeLabel.textAlignment = .center
        remakeLabel.font = UIFont.systemFont(ofSize: 10)
        remakeLabel.isHidden = true
        return remakeLabel
    }()
    
    //显示照片
    lazy var accordingPhoto: UIImageView = {
        let accordingPhoto = UIImageView(frame: view.frame)
        accordingPhoto.backgroundColor = .clear
        accordingPhoto.isHidden = true
        return accordingPhoto
    }()
    
    //自定义相机
    //初始化AVCaptureSession对象
    private let captureSession = AVCaptureSession()
    private var currentCameraPosition: AVCaptureDevice.Position = .back
    private var backCamera: AVCaptureDevice?
    private var frontCamera: AVCaptureDevice?
    private var backCameraInput: AVCaptureDeviceInput?
    private var frontCameraInput: AVCaptureDeviceInput?
    private let photoOutput = AVCapturePhotoOutput()
    func creatCamera() {
        //获取摄像设备
        let session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
        let availableCameraDevices = session.devices.compactMap { $0 }
        if !availableCameraDevices.isEmpty {
            for camera in availableCameraDevices {
                if camera.position == .back {
                    backCamera = camera
                } else if camera.position == .front {
                    frontCamera = camera
                }
            }
        }
        if let backCamera = self.backCamera {
            backCameraInput = try? AVCaptureDeviceInput(device: backCamera)
            if captureSession.canAddInput(backCameraInput!) {
                captureSession.addInput(backCameraInput!)
            }
            self.currentCameraPosition = .back
        } else if let frontCamera = self.frontCamera {
            frontCameraInput = try? AVCaptureDeviceInput(device: frontCamera)
            if captureSession.canAddInput(frontCameraInput!) {
                captureSession.addInput(frontCameraInput!)
            }
            self.currentCameraPosition = .front
        }
        
        if #available(iOS 11.0, *) {
            photoOutput.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecType.jpeg])], completionHandler: nil)
        } else {
            // Fallback on earlier versions
        }
        if captureSession.canAddOutput(photoOutput) {
            captureSession.addOutput(photoOutput)
        }

        let prevideLayer = AVCaptureVideoPreviewLayer(session: captureSession)
        prevideLayer.videoGravity = .resizeAspectFill
        prevideLayer.connection?.videoOrientation = .portrait
        prevideLayer.frame = view.frame
        view.layer.insertSublayer(prevideLayer, at: 0)
    }
    
    func switchCamera(position: AVCaptureDevice.Position)  {
        currentCameraPosition = position
        captureSession.beginConfiguration()
        switch currentCameraPosition {
        case .front:
            switchToBackCamera()
        case .back:
            switchToFrontCamera()
        default :
            break
        }
        captureSession.commitConfiguration()
    }
    
    //显示前置摄像头
    private func switchToFrontCamera() {
        if let backCameraInput = self.backCameraInput, captureSession.inputs.contains(backCameraInput), let frontCamera = self.frontCamera {
            self.frontCameraInput = try? AVCaptureDeviceInput(device: frontCamera)
            captureSession.removeInput(backCameraInput)
            if captureSession.canAddInput(self.frontCameraInput!) {
                captureSession.addInput(self.frontCameraInput!)
                
                self.currentCameraPosition = .front
            }
        }
    }
    
    //显示后置摄像头
    private func switchToBackCamera() {
        if let frontCameraInput = self.frontCameraInput, captureSession.inputs.contains(frontCameraInput), let backCamera = self.backCamera {
            self.backCameraInput = try? AVCaptureDeviceInput(device: backCamera)
            captureSession.removeInput(frontCameraInput)
            if captureSession.canAddInput(self.backCameraInput!) {
                captureSession.addInput(self.backCameraInput!)
                
                self.currentCameraPosition = .back
            }
        }
    }

    //MARK: -点击事件
    @objc func startBtnClick(sender: UIButton) {
        if isFinish {
            //根据当前设备的方向来设置拍照的方向
            let captureConnection = photoOutput.connection(with: .video)
            if (captureConnection?.isVideoOrientationSupported) != nil {
                captureConnection?.videoOrientation = self.getCaptureVideoOrientation(orientation: currentDirection.rawValue)
            }
            //拍照
            let settings = AVCapturePhotoSettings()
            if currentCameraPosition == .front {
                settings.flashMode = .off
            } else {
                settings.flashMode = isFlash
            }
            photoOutput.capturePhoto(with: settings, delegate: self)
            
            startButton.setImage(finshedImage, for: .normal)
            isFinish = !isFinish
            //隐藏底部视图
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "bottonSelect"), object: self, userInfo: ["hidden": 1])
        }
        
    }
    
    //设置录制视频方向
    func getCaptureVideoOrientation(orientation: Int) -> AVCaptureVideoOrientation {
        var result: AVCaptureVideoOrientation?
  
        switch orientation {
        case 1: break
        case 2:
            result = AVCaptureVideoOrientation.portrait
        case 4:
            result = AVCaptureVideoOrientation.landscapeRight
        case 3:
            result = AVCaptureVideoOrientation.landscapeLeft
        default:
            result = AVCaptureVideoOrientation.portrait
        }
        return result ?? AVCaptureVideoOrientation.portrait
    }
    
    //拍好了
    @objc func finshedBtnAction(sender:UIButton) -> Void {
        deviceOrientation.stop()
        self.selectedHandler?(selectImage!)
    }
    
    //重拍
    @objc func returnButtonAction() {
        deviceOrientation.start()
        isFinish = true
        startButton.setImage(startImage, for: .normal)
        hiddenView()
        //隐藏底部视图
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "bottonSelect"), object: self, userInfo: ["hidden": 0])
    }
    
    //显示视图
    private func showView() {
        finshedBtn.isHidden = false
        finshedLabel.isHidden = false
        backButton.isHidden = false
        remakeLabel.isHidden = false
        accordingPhoto.isHidden = false
    }
    
    //隐藏视图
    private func hiddenView() {
        finshedBtn.isHidden = true
        finshedLabel.isHidden = true
        backButton.isHidden = true
        remakeLabel.isHidden = true
        accordingPhoto.isHidden = true
    }
}

//MARK: -AVCapturePhotoCaptureDelegate代理方法
@available(iOS 10.0, *)
extension TakingPicturesViewController: AVCapturePhotoCaptureDelegate {
    @available(iOS 11.0, *)
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        if let imageData = photo.fileDataRepresentation() {
            let image = UIImage(data: imageData)
            accordingPhoto.image = image
            showView()
            
            selectImage = image
        }
        
    }
}
